/***socket.cpp
 *	2011.11.4, liyang
 *	Version 1.0
 *	implement recv information from server and send information to server
 ***/

#include "socket.h"
#include "xmlParse.h"

char g_serialnum[22];							//serianum
char g_serverip[17];							//serverip
char g_elecendtime[12];							//endtime for elec
char g_powerendtime[12];						//endtime for power
int g_serverport;								//serverport
int g_connectflag=0;							//0 if socket is outline or 1 connect successfully

extern struct StRecvCmd g_recvcmd[MAXCMD];		//recv cmd,recv from server send to mem
extern struct StSendMsg g_sendmsg[MAXCMD];		//send msg,recv from mem send to server
extern void myDelay(int);

/***socketHandler biref recv information from server and send information to server
 * 2012.02.22, liyang
 * param void
 *
 * retval void
 * Version 4.0
 **********************************************************************************
 * liyang	2012.02.22	v4.0	clear endtime for elec or power!
 ***/
void socketHandler()
{
	int l_strlen;											//str len
	int l_temp=0;											//the number of cmd/msg
	int l_number_r=0;										//recv number
	int l_number_s=0;										//send number
	int l_return;											//return of function
	int l_socket_fd;										//socket descriptor
	char l_recv_buf[MAXLEN],l_send_buf[MAXLEN];				//buf of recv/send
	struct sockaddr_in server_addr;							//argumnet of socketaddr_in

	//argument of function select
	fd_set l_wrfds,l_rdfds;									//write/read descriptor

	//set argumnet of sockaddr_in
	server_addr.sin_family=AF_INET;							//address family IPV4
	server_addr.sin_port=htons(g_serverport);				//port number
	//use inet_addr
	server_addr.sin_addr.s_addr=inet_addr(g_serverip);		//IPv4 address
//	//use inet_aton
//	if (0 == inet_aton(g_serverip,&server_addr.sin_addr))	//IPv4 address
//		ERROROUT("inet_aton error");
//	//use inet_pton
//	if (-1 != inet_pton(AF_INET,g_serverip,&server_addr.sin_addr))	//IPv4 address
//		ERROROUT("inet_pton error");
	bzero(&(server_addr.sin_zero),8);						//filler, all 0

	//set socket -> TCP
	if (-1 == (l_socket_fd=socket(AF_INET,SOCK_STREAM,0)))
	{
		ERROROUT("socket error");
		exit(-1);
	}

	//monitor tcp link
	setKeepAlive(l_socket_fd);

	//connect to server
	g_connectflag=0;
	//begin to connect to server
	BEGIN:
	if (-1 == (connect(l_socket_fd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr))))
	{
		//reconnect
		PRINTOUT("%s","connect error,retry now......\n");
		connectRetry(l_socket_fd,server_addr);
		g_connectflag=1;
		for (int i=0;i<10;i++)
		{
			g_elecendtime[i]='0';
			g_powerendtime[i]='0';
		}
		g_elecendtime[10]='\0';
		g_powerendtime[10]='\0';
		PRINTOUT("%s","connect successfully\n");

	}
	g_connectflag=1;
	for (int i=0;i<10;i++)
	{
		g_elecendtime[i]='0';
		g_powerendtime[i]='0';
	}
	g_elecendtime[10]='\0';
	g_powerendtime[10]='\0';

	//if connect successfully, send registration information to server
	REGIST:	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Regist~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
	PRINTOUT("%s","~~~~~~~~~~~~~~~~~~start regist~~~~~~~~~~~~~~~~~~~~\n");

	//send registration information
	memcpy(&l_send_buf[4],g_serialnum,20);
	l_send_buf[0]='#';
	l_send_buf[1]='r';
	l_send_buf[2]='s';
	l_send_buf[3]='#';
	l_send_buf[24]='#';
	l_send_buf[25]='\0';
	PRINTOUT("send registration is:%s\n",l_send_buf);
	if ( -1 == sendToServer(l_socket_fd,l_wrfds,l_send_buf))
		PRINTOUT("%s","send registration to server failed!\n");
	l_send_buf[0]='\0';

	//recv
	for (int i=0;i<5000;i++)									//try 5000 times,if don't recv registration,retry Regist
	{
		l_recv_buf[0]='\0';
		l_return=recvFromServer(l_socket_fd,l_rdfds,l_recv_buf);
		if (1 == l_return)										//server is out
		{
			PRINTOUT("%s","connectretry\n");
			connectRetry(l_socket_fd,server_addr);
			g_connectflag=1;
			for (int i=0;i<10;i++)
			{
				g_elecendtime[i]='0';
				g_powerendtime[i]='0';
			}
			g_elecendtime[10]='\0';
			g_powerendtime[10]='\0';
			goto REGIST;
		}
		if (0 == l_return)										//recv ok
		{
			//exit if "#ff#..."
			if ('f' == l_recv_buf[1] && 'f' == l_recv_buf[2])
			{
			PRINTOUT("%s","The illegal user, please reconfigure your serialNUM!\n");
				exit(-1);
			}
			//sleep 1 min if "#reboot#..."
			if ('r' == l_recv_buf[1] && 'e' == l_recv_buf[2] && 'b' == l_recv_buf[3] && 'o' == l_recv_buf[4] && 'o' == l_recv_buf[5] && 't' == l_recv_buf[6])
			{
				PRINTOUT("%s","server will reboot!\n");
				close(l_socket_fd);
				g_connectflag=0;
				sleep(60);
				goto BEGIN;
			}
			//regist cmd is "#rs#..."
			if ('r' == l_recv_buf[1] && 's' == l_recv_buf[2])
			{
				PRINTOUT("recv registration is:%s\n",l_recv_buf);
				PRINTOUT("%s","~~~~~~~~~~~~~~~~~~finish regist~~~~~~~~~~~~~~~~~~~\n");
				goto START;		//regist successfully, start recv cmd.
			}
		}
	}
	//if don't recv registration,retry Regist
	goto REGIST;

	START:	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Data transmission~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//

	while(1)
	{
		//recv from server
		l_recv_buf[0]='\0';
		l_return=recvFromServer(l_socket_fd,l_rdfds,l_recv_buf);
		if (1 == l_return)										//server is out
		{
			PRINTOUT("%s","connectretry\n");
			connectRetry(l_socket_fd,server_addr);
			g_connectflag=1;
			for (int i=0;i<10;i++)
			{
				g_elecendtime[i]='0';
				g_powerendtime[i]='0';
			}
			g_elecendtime[10]='\0';
			g_powerendtime[10]='\0';
			goto REGIST;
		}
		if (0 == l_return)										//recv ok
		{
			//exit if "#ff#..."
			if ('f' == l_recv_buf[1] && 'f' == l_recv_buf[2])
			{
				printf("The illegal user, please reconfigure your serialNUM!\n");
				exit(-1);
			}
			//sleep 1 min if "#reboot#..."
			else if ('r' == l_recv_buf[1] && 'e' == l_recv_buf[2] && 'b' == l_recv_buf[3] && 'o' == l_recv_buf[4] && 'o' == l_recv_buf[5] && 't' == l_recv_buf[6])
			{
				PRINTOUT("%s","server will reboot!\n");
				close(l_socket_fd);
				g_connectflag=0;
				sleep(60);
				goto BEGIN;
			}
			//save recv cmd in struct g_recvcmd
			else if ('t' == l_recv_buf[1] && 't' == l_recv_buf[2])
			{
				PRINTOUT("recv is:%s\n",l_recv_buf);
				for (int i=0;i<MAXCMD;i++)
				{
					//if g_recvcmd can be written
					if (false == g_recvcmd[l_number_r].flag)
					{
						l_strlen=0;
						//save strlen
						l_temp=4;
						while('#' != l_recv_buf[l_temp])
							l_temp++;
						l_strlen=l_temp-4;
						//save l_temp
						l_temp=0;
						while('\0' != l_recv_buf[l_temp])
							l_temp++;
						//save recv_cmd into l_recv_buf.
						memcpy(g_recvcmd[l_number_r].cmd,l_recv_buf,4+l_strlen);
						memcpy(&g_recvcmd[l_number_r].cmd[4+l_strlen],&l_recv_buf[25+l_strlen],l_temp-24-l_strlen);
						g_recvcmd[l_number_r].cmd[l_temp-21]='\0';
						g_recvcmd[l_number_r].flag=true;
						if (MAXCMD == l_number_r+1)
							l_number_r=0;
						else
							l_number_r++;
						break;
					}
					else
					{
						if (MAXCMD == l_number_r+1)
							l_number_r=0;
						else
							l_number_r++;
					}
				}
			}
			else
			{
				PRINTOUT("recv is:~~~~~%s~~~~~\n",l_recv_buf);
				PRINTOUT("%s","please input right cmd!\n");
			}
		}

		//send to server
		for (int i=0;i<MAXCMD;i++)
		{
			//if g_sendmsg have return messages
			
			if (true == g_sendmsg[l_number_s].flag)
			{
			LOGI("socketHandler = %s",g_sendmsg[l_number_s].msg);
				l_temp=0;
				while('\0'!= g_sendmsg[l_number_s].msg[l_temp])
					l_temp++;
				//write return messages into l_send_buf
				memcpy(l_send_buf,g_sendmsg[l_number_s].msg,l_temp);
				l_send_buf[l_temp]='\0';
				PRINTOUT("send is:%s\n",l_send_buf);
				//send return messages
				if ( -1 == sendToServer(l_socket_fd,l_wrfds,l_send_buf))
				{
					printf("send to server failed!\n");
					g_sendmsg[l_number_s].retrytimes++;
					if ( 3 == g_sendmsg[l_number_s].retrytimes)
					{
						printf("do not try again!!\n");
						/*20120222; clear endtime for elec or power ;Start*/
						if ( 'r' == l_send_buf[1] && 'e' == l_send_buf[2])
						{
							if ( '3' == l_send_buf[40] )
							{
								for (int i=0;i<10;i++)
								{
									g_elecendtime[i]='0';
								}
								g_elecendtime[10]='\0';
							}
							if ( '2' == l_send_buf[40] )
							{
								for (int i=0;i<10;i++)
								{
									g_powerendtime[i]='0';
								}
								g_powerendtime[10]='\0';
							}
						}
						/*20120222; clear endtime for elec or power ;End*/
						g_sendmsg[l_number_s].retrytimes=0;

						g_sendmsg[l_number_s].flag=false;
						if (MAXCMD == l_number_s+1)
							l_number_s=0;
						else
							l_number_s++;
					}
					break;
				}
				else
					g_sendmsg[l_number_s].flag=false;
				if (MAXCMD == l_number_s+1)
					l_number_s=0;
				else
					l_number_s++;
				break;
			}
			else
			{
				if (MAXCMD == l_number_s+1)
					l_number_s=0;
				else
					l_number_s++;
			}
		}

		myDelay(5);
	}

	close(l_socket_fd);
}

/***sendToServer() biref send information to server
 * 2011.11.4, liyang
 * param l_socket_fd[in], socket descriptor
 * param l_wrfds[in], write descriptor
 * param l_send_buf[in][out], buf of send
 *
 * retval, 0 if successful or -1 failed
 * Version 1.0
 ***/
int sendToServer(int l_socket_fd,fd_set l_wrfds,char *l_send_buf)
{
	struct timeval s_time={0,0};

	FD_CLR(l_socket_fd,&l_wrfds);
	FD_ZERO(&l_wrfds);
	FD_SET(l_socket_fd,&l_wrfds);
	if ( -1 == (select(l_socket_fd+1,NULL,&l_wrfds,NULL,&s_time)))
	{
		FD_CLR(l_socket_fd,&l_wrfds);
		return -1;
	}
	if (FD_ISSET(l_socket_fd,&l_wrfds))
	{
		if ( -1 == (write(l_socket_fd,l_send_buf,768)) )
		{
			FD_CLR(l_socket_fd,&l_wrfds);
			return -1;
		}
		else
//			;
			PRINTOUT("%s","send successfully!\n");
	}
	FD_CLR(l_socket_fd,&l_wrfds);
	return 0;
}

/***recvFromServer() biref recv information from server
 * 2011.11.4, liyang
 * param l_socket_fd[in], socket descriptor
 * param l_wrfds[in], write descriptor
 * param l_recv_buf[in][out], buf of recv
 *
 * retval, 0 if successful. -1 failed or 1 reconnect
 * Version 1.0
 ***/
int recvFromServer(int l_socket_fd,fd_set l_rdfds,char *l_recv_buf)
{
	int l_return;					//select return
	struct timeval s_time={0,1000};
	FD_CLR(l_socket_fd,&l_rdfds);
	FD_ZERO(&l_rdfds);
	FD_SET(l_socket_fd,&l_rdfds);
	l_return=select(l_socket_fd+1,&l_rdfds,NULL,NULL,&s_time);
	if ( (-1 == l_return) || (0 == l_return) )
	{
		FD_CLR(l_socket_fd,&l_rdfds);
		return -1;
	}
	if (FD_ISSET(l_socket_fd,&l_rdfds))
	{
		memset(l_recv_buf,0,MAXLEN);
		l_return=recv(l_socket_fd,l_recv_buf,MAXLEN,0);
		//monitor tcp link,-1 out line . next time select will return 1 and recv return 0
		if (-1 == l_return)
		{
			printf("out line!!!\n");
			FD_CLR(l_socket_fd,&l_rdfds);
			return -1;
		}
		//server is out
		if (0 == l_return)
		{
			printf("server is out line!!!\n");
			FD_CLR(l_socket_fd,&l_rdfds);
			return 1;
		}
		else
			;
//			printf("recv successfully!\n");
	}
	else
	{
		FD_CLR(l_socket_fd,&l_rdfds);
		return -1;
	}
	FD_CLR(l_socket_fd,&l_rdfds);
	return 0;
}

/***getMacAddr() biref get local device's Mac address
 * 2011.11.4, liyang
 * param l_socket_fd[in], socket descriptor
 * param l_l_mac_addr[in][out], buf of MacAddr
 *
 * retval, 0 if successful or -1 failed
 * Version 1.0
 ***/
int getMacAddr(int l_socket_fd,char* l_mac_addr)
{
	struct ifreq ifr_mac;
	memset(&ifr_mac,0,sizeof(ifr_mac));
	strncpy(ifr_mac.ifr_name, "eth0", sizeof(ifr_mac.ifr_name)-1);
	if( (ioctl( l_socket_fd, SIOCGIFHWADDR, &ifr_mac)) < 0)
	{
		printf("mac ioctl error\n");
		return -1;
	}
	sprintf(l_mac_addr,"%02x%02x%02x%02x%02x%02x",
			(unsigned char)ifr_mac.ifr_hwaddr.sa_data[0],
			(unsigned char)ifr_mac.ifr_hwaddr.sa_data[1],
			(unsigned char)ifr_mac.ifr_hwaddr.sa_data[2],
			(unsigned char)ifr_mac.ifr_hwaddr.sa_data[3],
			(unsigned char)ifr_mac.ifr_hwaddr.sa_data[4],
			(unsigned char)ifr_mac.ifr_hwaddr.sa_data[5]);

	return 0;
}

/***connectRetry() biref reconnect
 * 2011.11.5, liyang
 * param l_socket_fd[in], socket descriptor
 * param server_addr[in], argumnet of socketaddr_in
 *
 * retval void
 * Version 1.0
 ***/
void connectRetry(int l_socket_fd,struct sockaddr_in server_addr)
{
	int l_sec=1;				//sleep time
	g_connectflag=0;

	//close socket
	close(l_socket_fd);

	//reopen socket
	if (-1 == (l_socket_fd=socket(AF_INET,SOCK_STREAM,0)))
		{
			ERROROUT("socket error");
		}
	setKeepAlive(l_socket_fd);
	while(1)
	{
		printf("wait...\n");
		//connect
		if ( -1 == connect(l_socket_fd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)) )
		{
			if (l_sec < MAXSLEEP)
			{
				printf("connect error,retry after %dsec......\n",l_sec);
				sleep(l_sec);
				l_sec<<=1;
			}
			else	//if l_sec<MAXSLEEP,set l_sec=1
			{
				printf("connect error,retry after %dsec......\n",l_sec);
				sleep(l_sec);
				l_sec=1;
			}
		}
		else
			break;
	}
}

/***setKeepAlive() biref monitor tcp link
 * 2011.11.7, liyang
 * param l_socket_fd[in], socket descriptor
 *
 * retval void
 * Version 1.0
 ***/
void setKeepAlive(int l_socket_fd)
{
	socklen_t l_keepalive=1;		//set keepalive
	socklen_t l_keepidle=5;			//the beginning of the first keepalive detection before the TCP air closing time
	socklen_t l_keepinterval=5;		//two keepalive detection interval
	socklen_t l_keepcount=3;		//determination of disconnected before the keepalive detection times

	setsockopt( l_socket_fd , SOL_SOCKET , SO_KEEPALIVE , (const char*)&l_keepalive , sizeof(l_keepalive) );
	setsockopt( l_socket_fd , SOL_TCP , TCP_KEEPIDLE , (const char*)&l_keepidle , sizeof(l_keepidle) );
	setsockopt( l_socket_fd , SOL_TCP , TCP_KEEPINTVL , (const char*)&l_keepinterval , sizeof(l_keepinterval) );
	setsockopt( l_socket_fd , SOL_TCP , TCP_KEEPCNT , (const char*)&l_keepcount , sizeof(l_keepcount) );
}


int init_config_file()
{
    FILE *fp = NULL;

	fp = fopen(SERVERPATHPPC,"w+");
    if(NULL == fp)
	{
		ERROROUT("open config file fail.\n!");
		return -1;
	}

	fwrite(DEFALUT_SERVER_IP,sizeof(DEFALUT_SERVER_IP),1,fp);
	fwrite(DEFALUT_SERVER_PORT,sizeof(DEFALUT_SERVER_PORT),1,fp);
	fwrite(DEFALUT_SER_NUM,sizeof(DEFALUT_SER_NUM),1,fp);

	fclose(fp);

	printf("init_config_file successfully.");
    return 0;
}

/***getSeriaNum() biref get g_serialnum from sqlite
 * 2011.12.20, liyang
 * param g_serialnum[in][out],serialnum
 * param g_serverip[in][out],serverip
 * param g_serverport[in][out],serverport
 *
 * retval 0 if successful or -1 failed
 * Version 2.0
 ***/
 int getSerialNum(char *g_serialnum,char *g_serverip,int &g_serverport)
{
	guodian_s temp;
	getserial(&temp);
	
	memcpy(g_serverip,temp.serverip,strlen(temp.serverip));
	g_serverip[strlen(temp.serverip)] = '\0';
	
	g_serverport = atoi(temp.serverport);
	
	
	
	memcpy(g_serialnum,temp.gatawaysn,strlen(temp.gatawaysn));
	g_serialnum[strlen(g_serialnum)] = '\0';
	return 0;
}
/*int getSerialNum(char *g_serialnum,char *g_serverip,int &g_serverport)
{
	int l_openserver;
	int l_temp1,l_temp2;
	char l_buf[100];
	char l_serverport[7];

	if (-1 == (l_openserver=open(SERVERPATHARM,O_RDONLY)))
	{
		if (-1 == (l_openserver=open(SERVERPATHPPC,O_RDONLY)))
		{
			if(-1 == init_config_file())
			{
    			ERROROUT("open serverconfig error!");
		    	return -1;				
			}
			else
			{
				l_openserver=open(SERVERPATHPPC,O_RDONLY);
			}
		}
	}

	if (-1 == read(l_openserver,l_buf,100))
	{
		ERROROUT("read error!");
		return -1;
	}

	//get serverip
	l_temp1=0;
	while('=' != l_buf[l_temp1])
		l_temp1++;
	l_temp1++;
	l_temp2=0;
	while('\n' != l_buf[l_temp2])
		l_temp2++;
	memcpy(g_serverip,&l_buf[l_temp1],l_temp2-l_temp1);
	g_serverip[l_temp2-l_temp1]='\0';
	if ('\0' == g_serverip[0])
	{
		printf("please config serverip first!\n");
		return -1;
	}

	//get serverport
	while('=' != l_buf[l_temp2])
		l_temp2++;
	l_temp1=++l_temp2;
	while('\n' != l_buf[l_temp2])
		l_temp2++;
	memcpy(l_serverport,&l_buf[l_temp1],l_temp2-l_temp1);
	g_serverport=atoi(l_serverport);
	if (0 == g_serverport)
	{
		printf("please config serverport first!\n");
		return -1;
	}

	//get serialnum
	while('=' != l_buf[l_temp2])
		l_temp2++;
	l_temp1=++l_temp2;
	while('\n' != l_buf[l_temp2] && '\0' != l_buf[l_temp2])
		l_temp2++;
	memcpy(g_serialnum,&l_buf[l_temp1],l_temp2-l_temp1);
	g_serialnum[l_temp2-l_temp1]='\0';
	if ('\0' == g_serialnum[0])
	{
		printf("please config serialnum first!\n");
		return -1;
	}

	return 0;
}*/
